package com.baoyouqun.service.impl;

import cn.hutool.core.collection.CollUtil;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baoyouqun.API.push.WechatService;
import com.baoyouqun.API.push.mini.WxMiniSubscribeService;
import com.baoyouqun.base.utils.ExcelTool;
import com.baoyouqun.domain.Query.WechatPushQuery;
import com.baoyouqun.domain.VO.WechatPushDTO;
import com.baoyouqun.domain.VO.WechatPushVO;
import com.baoyouqun.entity.City;
import com.baoyouqun.entity.User;
import com.baoyouqun.entity.UserVipTime;
import com.baoyouqun.entity.WechatPushRecord;
import com.baoyouqun.mapper.CityMapper;
import com.baoyouqun.mapper.WechatPushRecordMapper;
import com.baoyouqun.service.UserService;
import com.baoyouqun.service.UserVipTimeService;
import com.baoyouqun.service.WechatPushService;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.util.StringUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WechatPushServiceImpl extends ServiceImpl<WechatPushRecordMapper, WechatPushRecord>
        implements WechatPushService {

    @Resource
    private UserService userService;
    @Resource
    private UserVipTimeService userVipTimeService;
    @Resource
    private CityMapper cityMapper;
    @Resource
    private WechatService wechatService;

    @Resource
    private WxMiniSubscribeService wxMiniSubscribeService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void createPush(WechatPushDTO dto, String operatorId) {
        // 1. 获取符合条件的用户ID列表
        List<String> userIds = getUserIdsByFilter(dto);
        if (CollUtil.isEmpty(userIds)) {
            throw new RuntimeException("没有符合条件的推送用户");
        }

        // 2. 保存推送记录
        WechatPushRecord record = new WechatPushRecord();
        record.setTitle(dto.getTitle());
        record.setContent(dto.getContent());
        record.setFilterConditions(JSON.toJSONString(dto));
        record.setPushTime(LocalDateTime.now());
        record.setStatus(1); // 假设立即推送
        record.setUserCount(userIds.size());
        record.setCreateBy(operatorId);
        record.setCreateTime(LocalDateTime.now());
        save(record);

        // 3. 调用微信服务推送消息
//        wechatService.pushToUsers(dto.getTitle(), dto.getContent(), userIds);

        // 构建模板数据（根据实际模板调整字段）
        // 1. 从user表直接查询用户的openid（关键调整：无需关联中间表）
        List<User> users = userService.list(Wrappers.<User>lambdaQuery()
                .in(User::getId, userIds)
                .isNotNull(User::getWxOpenid));
        // 提取有效的openid列表
        List<String> openids = users.stream()
                .map(User::getWxOpenid)
                .collect(Collectors.toList());
        Map<String, Object> data = new HashMap<>();
        data.put("thing6", Map.of("value", "新消息通知")); // 模板中的thing1字段
        data.put("thing2", Map.of("value", "新消息通知")); // 模板中的thing1字段
        data.put("time3", Map.of("value", "2024-05-20 12:00")); // 模板中的time2字段


        // 推送（openids为已授权的小程序用户openid列表）
        wxMiniSubscribeService.pushSubscribeMessage(openids, data);
    }


    @Override
    public IPage<WechatPushVO> pagePush(WechatPushQuery query) {
        Page<WechatPushRecord> page = new Page<>(query.getCurrent(), query.getSize());
        IPage<WechatPushRecord> recordPage = baseMapper.selectPage(page, Wrappers.<WechatPushRecord>lambdaQuery()
                .eq(query.getStatus() != null, WechatPushRecord::getStatus, query.getStatus())
                .like(StringUtil.isNotBlank(query.getContent()), WechatPushRecord::getContent, query.getContent())
                .orderByDesc(WechatPushRecord::getCreateTime)
        );

        Page<WechatPushVO> voPage = new Page<>(recordPage.getCurrent(), recordPage.getSize(), recordPage.getTotal());
        voPage.setRecords(recordPage.getRecords().stream()
                .map(WechatPushVO::fromEntity)
                .collect(Collectors.toList()));
        return voPage;
    }

    @Override
    public void exportPush(WechatPushQuery query, HttpServletResponse response) throws IOException {
        // 1. 查询所有符合条件的记录
        List<WechatPushRecord> records = baseMapper.selectList(Wrappers.<WechatPushRecord>lambdaQuery()
                .eq(query.getStatus() != null, WechatPushRecord::getStatus, query.getStatus())
                .like(StringUtil.isNotBlank(query.getContent()), WechatPushRecord::getContent, query.getContent())
                .orderByDesc(WechatPushRecord::getCreateTime)
        );

        // 2. 转换为导出数据
        List<WechatPushVO> voList = records.stream()
                .map(WechatPushVO::fromEntity)
                .collect(Collectors.toList());

        // 3. 使用Hutool导出Excel
        // 设置响应头，解决中文乱码和文件下载问题
        response.setContentType("application/vnd.ms-excel;charset=utf-8");
        String fileName = java.net.URLEncoder.encode("推送记录", StandardCharsets.UTF_8);
        ExcelTool.setExportFileName(response, "推送记录");
        // 创建ExcelWriter（true表示生成xlsx格式，false为xls）
        cn.hutool.poi.excel.ExcelWriter writer = cn.hutool.poi.excel.ExcelUtil.getWriter(true);
        // 重命名sheet
        writer.renameSheet("推送记录");

        // 可选：设置表头别名（如果需要自定义表头名称）
        // 例如：writer.addHeaderAlias("id", "记录ID");
        //      writer.addHeaderAlias("title", "推送标题");
        //      writer.addHeaderAlias("content", "推送内容");
        //      ...根据WechatPushVO的字段自行添加

        // 写入数据（第二个参数true表示包含表头）
        writer.write(voList, true);

        // 输出到响应流
        writer.flush(response.getOutputStream());

        // 关闭资源
        writer.close();
        cn.hutool.core.io.IoUtil.close(response.getOutputStream());
    }

    /**
     * 根据筛选条件获取用户ID列表
     */
    public List<String> getUserIdsByFilter(WechatPushDTO dto) {
        // 1. 基础查询条件
        List<String> userIds = userService.listObjs(Wrappers.<User>lambdaQuery()
                        .select(User::getId)
                        .eq(User::getDisEnable, false)
                        .eq(User::getLogout, false)
                        .ne(User::getWxOpenid, "")
                        .isNotNull(User::getWxOpenid)
                        .eq(dto.getBaoZhiHao() != null, User::getBaoZhiHao, dto.getBaoZhiHao()) // 假设存在baoZhiHao字段
                        .eq(StringUtil.isNotBlank(dto.getSex()), User::getSex, dto.getSex())
                        .in(CollUtil.isNotEmpty(dto.getIndustryList()), User::getIndustry, dto.getIndustryList()),
                obj -> (String) obj);

        if (CollUtil.isEmpty(userIds)) {
            return new ArrayList<>();
        }

        // 2. 会员筛选
        if (dto.getIsVip() != null) {
            Set<String> vipUserIds = userVipTimeService.list(Wrappers.<UserVipTime>lambdaQuery()
                            .gt(UserVipTime::getEndTime, LocalDateTime.now())
                            .in(UserVipTime::getUserId, userIds))
                    .stream()
                    .map(UserVipTime::getUserId)
                    .collect(Collectors.toSet());

            userIds = userIds.stream()
                    .filter(id -> dto.getIsVip() == vipUserIds.contains(id))
                    .collect(Collectors.toList());
        }

        // 3. 地区筛选（包含下级城市）
        if (StringUtil.isNotBlank(dto.getCityCode())) {
            List<String> allCityCodes = getAllSubCityCodes(dto.getCityCode());
            allCityCodes.add(dto.getCityCode()); // 包含自身

            userIds = userService.listObjs(Wrappers.<User>lambdaQuery()
                            .select(User::getId)
                            .in(User::getCityCode, allCityCodes)
                            .in(User::getId, userIds),
                    obj -> (String) obj);
        } else {
            dto.setCityCode("全国");
        }

        return userIds;
    }

    /**
     * 递归获取所有下级城市编码
     */
    private List<String> getAllSubCityCodes(String parentCode) {
        List<City> childCities = cityMapper.selectList(Wrappers.<City>lambdaQuery()
                .eq(City::getParentCode, parentCode));

        if (CollUtil.isEmpty(childCities)) {
            return new ArrayList<>();
        }

        List<String> result = new ArrayList<>();
        for (City city : childCities) {
            result.add(city.getCode());
            result.addAll(getAllSubCityCodes(city.getCode())); // 递归获取下级
        }
        return result;
    }
}
